#include "Script.h"


Script::Script()
{
}

Script::~Script()
{
}

bool Script::Load(std::string Filename)
{
	FILE* f;
	f = fopen(Filename.c_str(),"rt");
	if (!f)
		return false;
	ScriptSegment S;
	while (true)
	{
		if (!S.LoadFrom(f))
			break;
		m_Segments.push_back(S);
	}

	fclose (f);
	return true;
}

bool Script::Save(std::string Filename)
{
	FILE* f;
	f = fopen(Filename.c_str(),"wt");
	if (!f)
		return false;
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (!it->WriteTo(f))
		{
			fclose(f);
			return false;
		}
			
	}
	fclose(f);
	return true;
}

void Script::CreateDefault(Demo& D)
{
	float Origin[3] = {0,0,0};
	float Angles[3] = {0,0,0};

	ScriptPoint P1(D.GetFirstTime(),Origin,Angles);
	ScriptPoint P2(D.GetLastTime(),Origin,Angles);

	ScriptSegment S(P1,P2);
	m_Segments.push_back(S);
}

void Script::UpdateCamera(float Time,float Origin[3],float Angles[3])
{
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetFromTime() <= Time && it->GetToTime() >= Time)
		{
			it->Interpolate(Time,Origin,Angles);
			break;
		}
	}
}


float Script::GetRatio(float Time)
{
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetFromTime() <= Time && it->GetToTime() >= Time)
		{	
			return it->GetRatio(Time);
		}
	}
	return -1;
}

void Script::SetPoint(float Time,float Origin[3],float Angles[3])
{
	ScriptPoint P(Time,Origin,Angles);


	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetFromTime() <= Time && it->GetToTime() >= Time)
		{			

			if (it->GetFromTime() == Time)
			{
				// just change the from position
				P.SetTime(it->GetFromTime());
				it->SetFrom(P);

				SegList::iterator it2 = it;
				it2++;
				if (it2 == m_Segments.end()) // if this segment is the last
				{
					P.SetTime(it->GetToTime());
					it->SetTo(P);
				}
			}
			else if (it->GetToTime() == Time)
			{
				// just change the to position
				it->SetTo(P);
				break;
			}
			else
			{
				ScriptSegment S(it->GetFrom(),P);
				it->SetFrom(P);
				SegList::iterator itt = it;
				itt++;
				if (itt == m_Segments.end())
				{
					P.SetTime(it->GetToTime());
					it->SetTo(P);
				}

				m_Segments.insert(it,S);
			}

		}
	}
}

void Script::RemovePoint(float Time)
{
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetToTime() == Time)
		{
			SegList::iterator it2 = it;
			
			if (++it2 == m_Segments.end())
				return;
			it->SetTo(it2->GetTo());
			m_Segments.erase(it2);
			break;
		}
	}
}

void Script::GotoPrevTime(float& time)
{
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetFromTime() < time && it->GetToTime() >= time)
		{			
			time = it->GetFromTime();
			return;
		}
	}
}
void Script::GotoNextTime(float& time)
{
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetFromTime() <= time && it->GetToTime() > time)
		{			
			time = it->GetToTime();
			return;
		}
	}
}

bool Script::IsPoint(float Time)
{
	SegList::iterator it;
	for (it = m_Segments.begin(); it != m_Segments.end(); it++)
	{
		if (it->GetFromTime() <= Time && it->GetToTime() >= Time)
		{
			return (Time == it->GetFromTime() || 
				Time == it->GetToTime());
		}
	}
	return false;
}


ScriptSegment::ScriptSegment(ScriptPoint From,ScriptPoint To)
	: m_From(From),m_To(To)
{
}

float ScriptSegment::GetRatio(float Time)
{
	return (Time - m_From.GetTime()) / (m_To.GetTime()-m_From.GetTime());
}


void ScriptSegment::Interpolate(float Time,float Origin[3],float Angles[3])
{


	float Ratio = GetRatio(Time);
	for (int I = 0; I < 3; I++)
	{
		Origin[I] = m_From.GetOrigin(I)*(1-Ratio) + m_To.GetOrigin(I)*(Ratio);
		float A1 = m_From.GetAngle(I);
		float A2 = m_To.GetAngle(I);
		if ((A2 - A1) > 180)
		{
			A1 = A1+360;
		}
		if ((A2 - A1) < -180)
		{
			A1 -= 360;
		}
		Angles[I] = A1*(1-Ratio) + A2*(Ratio);
		if (Angles[I] < 0)
			Angles[I] += 360;
		if (Angles[I] > 360)
			Angles[I] -= 360;

	}

	// do the a neat roll when the turn is sharp
	float Diff = (m_From.GetAngle(1) - m_To.GetAngle(1)) / Time;
	float Delta = m_To.GetTime() - m_From.GetTime();

	if (Delta > 0.05)
	{
		static float Roll = 0;
		Roll = (Roll*15 + (Diff / Delta)/10) / 16;
		Angles[2] = Roll;
	}
}

bool ScriptSegment::WriteTo(FILE* f)
{
	if (!m_From.WriteTo(f))
		return false;
	if (!m_To.WriteTo(f))
		return false;
	fprintf(f,"\n");
	return true;
}

bool ScriptSegment::LoadFrom(FILE* f)
{
	if (!m_From.LoadFrom(f))
		return false;
	if (!m_To.LoadFrom(f))
		return false;
	return true;
}

ScriptPoint::ScriptPoint(float Time, float Origin[3], float Angles[3])	: m_Time(Time)
{
	for (int I = 0; I < 3; I++)
	{
		m_Origin[I] = Origin[I];
		m_Angles[I] = Angles[I];
	}
}
bool ScriptPoint::WriteTo(FILE* f)
{
	return (fprintf(f,"%.6f:(%0.6f,%0.6f,%0.6f)->(%0.6f,%0.6f,%0.6f)   ",
		m_Time,m_Origin[0],m_Origin[1],m_Origin[2],
		m_Angles[0],m_Angles[1],m_Angles[2]) > 0);
}

bool ScriptPoint::LoadFrom(FILE* f)
{
	return (7 == fscanf(f,"%f:(%f,%f,%f)->(%f,%f,%f)   ",
		&m_Time,&m_Origin[0],&m_Origin[1],&m_Origin[2],
		&m_Angles[0],&m_Angles[1],&m_Angles[2]) );
}

